package k8s_ui

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/wonderivan/logger"
	nwv1 "k8s.io/api/networking/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var Ingress ingress

type ingress struct{}

// 定义ServiceCreate结构体，用于创建service需要传入的参数属性的定义
type IngressCreate struct {
	Name             string                 `json:"ingress_name"`
	Namespace        string                 `json:"namespace"`
	Annotations      map[string]string      `json:"annotations"`
	Label            map[string]string      `json:"label"`
	Hosts            map[string][]*HttpPath `json:"hosts"`
	IngressClassName *string                `json:"ingressclassname"`
}

// 定义ingress的path结构体
type HttpPath struct {
	Path        string        `json:"path"`
	PathType    nwv1.PathType `json:"path_type"`
	ServiceName string        `json:"service_name"`
	ServicePort int32         `json:"service_port"`
}

// 定义ServiceNp类型，用于返回namespace中Service的数量
type IngressNp struct {
	Namespace string `json:"ingressname"`
	DaemonNum int    `json:"ingress_num"`
}

type IngressResp struct {
	Items []nwv1.Ingress `json:"items"`
	Total int            `json:"total"`
}

// ingress列表
func (p *ingress) GetIngress(IngressName, namespace string, limit, page int) (ingressResp *IngressResp, err error) {
	//获取ServiceList类型的service列表
	ingressList, err :=
		K8s.ClientSet.NetworkingV1().Ingresses(namespace).List(context.TODO(),
			metav1.ListOptions{})
	if err != nil {
		logger.Error(errors.New("获取ingress列表失败, " + err.Error()))
		return nil, errors.New("获取ingress列表失败, " + err.Error())
	}

	//将ServiceList中的Service列表(Items)，放进dataselector对象中，进行排序
	selectableData := &DataSelector{
		GenericDataList: p.toCells(ingressList.Items),
		DataSelect: &DataSelectQuery{
			Filter: &FilterQuery{Name: IngressName},
			Paginate: &PaginateQuery{
				Limit: limit,
				Page:  page,
			},
		},
	}
	filtered := selectableData.Filter()
	total := len(filtered.GenericDataList)
	data := filtered.Sort().Paginate()
	//将[]DataCell类型的service列表转为service列表
	ingress := p.fromCells(data.GenericDataList)
	return &IngressResp{
		Items: ingress,
		Total: total,
	}, nil
}

// toCells方法用于将pod类型转成DataCell类型
func (*ingress) toCells(std []nwv1.Ingress) []DataCell {
	cells := make([]DataCell, len(std))
	for i := range std {
		//std[i]原生pod类型 -> podCell -> DataCell
		cells[i] = ingressCell(std[i])
	}
	return cells
}

// fromCells方法用于将DataCell类型转成pod类型
func (*ingress) fromCells(cells []DataCell) []nwv1.Ingress {
	services := make([]nwv1.Ingress, len(cells))
	for i := range cells {
		//cells[i] DataCell接口类型 -> podCell -> 原生pod类型
		services[i] = nwv1.Ingress(cells[i].(ingressCell))
	}
	return services
}

// 获取ingress详情
func (d *ingress) GetIngressDetail(ingressName, namespace string) (ingress *nwv1.Ingress, err error) {
	ingress, err =
		K8s.ClientSet.NetworkingV1().Ingresses(namespace).Get(context.TODO(), ingressName,
			metav1.GetOptions{})
	if err != nil {
		logger.Error(errors.New("获取Ingress详情失败, " + err.Error()))
		return nil, errors.New("获取Ingress详情失败, " + err.Error())
	}
	return ingress, nil
}

// 创建ingress,,接收ingressCreate对象
func (d *ingress) CreateIngress(data *IngressCreate) (err error) {
	//声明nwv1.IngressRule和nwv1.HTTPIngressPath变量，后面组装数据于鏊用到
	var ingressRules []nwv1.IngressRule
	var httpIngressPATHs []nwv1.HTTPIngressPath
	//Annotations默认值
	annotations := map[string]string{
		"nginx.ingress.kubernetes.io/rewrite-target": "/",
	}
	// 将修改后的值重新赋值给 map
	data.Annotations = annotations
	//将data中的数据组装成nwv1.Ingress对象
	ingress := &nwv1.Ingress{
		ObjectMeta: metav1.ObjectMeta{
			Name:        data.Name,
			Namespace:   data.Namespace,
			Labels:      data.Label,
			Annotations: data.Annotations,
		},
	}
	//第一层for循环是将host组装成nwv1.IngressRule类型的对象
	// 一个host对应一个ingressrule，每个ingressrule中包含一个host和多个path
	for key, value := range data.Hosts {
		ir := nwv1.IngressRule{
			Host: key,
			//这里现将nwv1.HTTPIngressRuleValue类型中的Paths置为空，后面组装好数据再赋值
			IngressRuleValue: nwv1.IngressRuleValue{
				HTTP: &nwv1.HTTPIngressRuleValue{Paths: nil},
			},
		}
		//第二层for循环是将path组装成nwv1.HTTPIngressPath类型的对象
		for _, httpPath := range value {
			hip := nwv1.HTTPIngressPath{
				Path:     httpPath.Path,
				PathType: &httpPath.PathType,
				Backend: nwv1.IngressBackend{
					Service: &nwv1.IngressServiceBackend{
						Name: httpPath.ServiceName,
						Port: nwv1.ServiceBackendPort{
							Number: httpPath.ServicePort,
						},
					},
				},
			}
			//将每个hip对象组装成数组
			httpIngressPATHs = append(httpIngressPATHs, hip)
		}
		//给Paths赋值，前面置为空了
		ir.IngressRuleValue.HTTP.Paths = httpIngressPATHs
		//清空上次数据重新接收新数据
		httpIngressPATHs = nil
		//将每个ir对象组装成数组，这个ir对象就是IngressRule，每个元素是一个host和多个path
		ingressRules = append(ingressRules, ir)
	}
	//将ingressRules对象加入到ingress的规则中
	ingress.Spec.Rules = ingressRules
	//ingress绑定IngressClass
	ingress.Spec.IngressClassName = data.IngressClassName

	//创建ingress
	_, err =
		K8s.ClientSet.NetworkingV1().Ingresses(data.Namespace).Create(context.TODO(), ingress,
			metav1.CreateOptions{})
	if err != nil {
		logger.Error(errors.New("创建Ingress失败, " + err.Error()))
		return errors.New("创建Ingress失败, " + err.Error())
	}
	return nil
}

// 删除service
func (d *ingress) DeleteIngress(ingressName, namespace string) (err error) {
	err = K8s.ClientSet.NetworkingV1().Ingresses(namespace).Delete(context.TODO(),
		ingressName, metav1.DeleteOptions{})
	if err != nil {
		logger.Error(errors.New("删除ingress失败, " + err.Error()))
		return errors.New("删除ingress失败, " + err.Error())
	}

	return nil
}

// 更新service
func (d *ingress) UpdateIngress(IngressSpaceName, content string) (err error) {
	var ingress = &nwv1.Ingress{}
	err = json.Unmarshal([]byte(content), ingress)
	if err != nil {
		logger.Error(errors.New("反序列化失败, " + err.Error()))
		return errors.New("反序列化失败, " + err.Error())
	}
	_, err = K8s.ClientSet.NetworkingV1().Ingresses(IngressSpaceName).Update(context.TODO(),
		ingress, metav1.UpdateOptions{})
	if err != nil {
		logger.Error(errors.New("更新ingress失败, " + err.Error()))
		return errors.New("更新ingress失败, " + err.Error())
	}
	return nil
}

// GetIngressClassName 返回集群中所有 IngressClass 的列表
func (p *ingress) GetIngressClassName() (*nwv1.IngressClassList, error) {
	ingressClasses, err := K8s.ClientSet.NetworkingV1().IngressClasses().List(context.TODO(), metav1.ListOptions{})
	if err != nil {
		logger.Error(errors.New("查询IngressClassName失败, " + err.Error()))
		return nil, errors.New("查询IngressClassName失败, " + err.Error())
	}
	return ingressClasses, nil
}
